﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using QUT.Bio.Graphs;
using QUT.Bio.Util;
using QUT.Bio.SilverMap.ObjectModel;
using System.Linq;

namespace QUT.Bio.SilverMap.DefaultProvider {
	/// <summary>
	/// This carries specific information about a Gene, plus also a bunch of properties that 
	/// adapt a Gene to allow it to act as a databinding source for the view.
	/// </summary>
	public class Gene : ILinearDomain, INotifyPropertyChanged {
		public static readonly string[] AdditionalGeneFields = { "Note", "Translation", "ProteinId" };

		private SequenceSource source = SequenceSource.MQUTeRSilverMap;
		private decimal id;
		private Chromosome chromosome;
		private string locusTag;
		private string symbol;
		private string product;
		private string translation;
		private string note;
		internal readonly List<Xref> xref = new List<Xref>();
		private long length;

		public event PropertyChangedEventHandler  PropertyChanged;

		public Gene (
			decimal id,
			Chromosome chromosome,
			string locusTag,
			string symbol,
			string product,
			long length
		) {
			this.id = id;
			this.chromosome = chromosome;
			this.locusTag = locusTag;
			this.symbol = symbol;
			this.product = product;
			this.length = length;
		}

		public decimal Id {
			get {
				return id;
			}
		}

		[Displayed]
		public string Accession {
			get {
				return chromosome.Accession;
			}
		}

		[Displayed]
		public string LocusTag {
			get {
				return locusTag;
			}
		}

		[Displayed]
		public string Symbol {
			get {
				return symbol;
			}
		}

		[Displayed]
		public string Product {
			get {
				return product;
			}
		}

		/// <summary>
		/// Gets the description of the containing chromosome.
		/// </summary>

		[Displayed]
		public string Description {
			get {
				return chromosome.Description;
			}
		}

		/// <summary>
		/// Get or set the Note and fire PropertyChanged.
		/// </summary>

		[Displayed]
		public string Note {
			get {
				return note;
			}
			set {
				if ( note != value ) {
					note = value;
					PropertyChanging( "Note" );
				}
			}
		}

		/// <summary>
		/// Get or set the Translation and notify property changed.
		/// </summary>

		[Displayed]
		public string Translation {
			get {
				return translation;
			}
			set {
				if ( translation != value ) {
					translation = value;
					PropertyChanging( "Translation" );
				}
			}
		}

		/// <summary>
		/// Get a textual representation of the Gene object.
		/// </summary>
		/// <returns>this.ToString().</returns>

		public override string ToString () {
			return String.Format( "{0}: {1} - {2}", LocusTag, Symbol, Product );
		}

		/// <summary>
		/// Gets a label to attach to the vertex view in a map.
		/// </summary>

		public string Label {
			get {
				return symbol == "" || symbol == null || symbol == "n/a" || symbol == "unavailable"
				? Accession + "-" + LocusTag
				: Accession + "-" + symbol;
			}
		}

		/// <summary>
		/// Get the name, by merging the model's accession with the locus tag.
		/// </summary>

		public string Name {
			get {
				return string.Format( "{0}: {1}", chromosome.Description, LocusTag );
			}
		}

		public IEnumerable<Xref> Xref {
			get {
				return xref;
			}
		}

		public int CompareTo ( ILinearDomain other ) {
			if ( other is Gene ) {
				Gene otherGene = (Gene) other;
				int result = chromosome.CompareTo( otherGene.chromosome );

				if ( result == 0 ) {
					result = locusTag.CompareTo( otherGene.LocusTag );
				}

				return result;
			}
			else {
				return GetHashCode().CompareTo( other.GetHashCode() );
			}
		}
		
		public int CompareTo( object x ) {
			return CompareTo((ILinearDomain) x);
		}

		public bool Equals( ILinearDomain other ) {
			return CompareTo( other ) == 0;
		}

		public override bool Equals ( object obj ) {
			return Equals( (ILinearDomain) obj );
		}

		public override int GetHashCode () {
			return chromosome.GetHashCode() << 5 + locusTag.GetHashCode();
		}
		
		private void PropertyChanging ( string propertyName ) {
			if ( PropertyChanged != null ) {
				PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
			}
		}

		public string SequenceData {
			get {
				return Translation;
			}
		}

		public Chromosome Chromosome {
			get {
				return chromosome;
			}
		}

		[Displayed]
		public long Length {
			get {
				return length;
			}
		}

		[Displayed]
		public string GI {
			get {
				var result = ( from Xref xref in this.Xref where xref.Database.Equals( "GI" ) select xref.Id ).FirstOrDefault();
				
				if ( result == null ) {
					result = "n/a";
				}
				
				return result;
			}
		}

		public SequenceSource Source {
			get {
				return source;
			}
		}

		string ILinearDomain.Id {
			get {
				return id.ToString();
			}
		}
	}
}
